﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
namespace YanZhiwei.DotNet2.Utilities.Common
{
    /// <summary>
    /// string帮助类
    /// </summary>
    public static class StringHelper
    {
        #region 为指定格式的字符串填充相应对象来生成字符串
        /// <summary>
        /// 为指定格式的字符串填充相应对象来生成字符串
        /// </summary>
        /// <param name="format">字符串格式，占位符以{n}表示</param>
        /// <param name="args">用于填充占位符的参数</param>
        /// <returns>格式化后的字符串</returns>
        public static string FormatWith(this string format, params object[] args)
        {
            return string.Format(CultureInfo.CurrentCulture, format, args);
        }
        #endregion 
        #region 字符串逆转
        /// <summary>
        /// 字符串逆转
        /// <para>eg:StringHelper.Reverse("YanZhiwei");</para>
        /// </summary>
        /// <param name="data">需要逆转的字符串</param>
        /// <returns>逆转后的字符串</returns>
        public static string Reverse(this string data)
        {
            if (!string.IsNullOrEmpty(data))
            {
                char[] _chars = data.ToCharArray();
                Array.Reverse(_chars);
                return new string(_chars);
            }
            return data;
        }
        #endregion
        #region 将时间的BCD码转换表述形式
        /// <summary>
        ///<para>eg:StringHelper.FormatDateTimeBCD("22212018111220")==>2012-11-18 20:21:22</para>
        /// </summary>
        /// <param name="dateTime">表示时间的BCD码</param>
        /// <returns>CD码</returns>
        public static string FormatDateTimeBCD(this string dateTime)
        {
            dateTime = dateTime.Trim();
            if (dateTime.Length != 14)
                throw new ArgumentException("需要14个长度的时间类型字符串！");
            string _second = dateTime.Substring(0, 2);//秒
            string _minute = dateTime.Substring(2, 2);//分
            string _hour = dateTime.Substring(4, 2);//小时
            string _day = dateTime.Substring(6, 2);//天
            string _month = dateTime.Substring(8, 2);//月
            string _yearPart1 = dateTime.Substring(10, 2);//年
            string _yearPart2 = dateTime.Substring(12, 2);//年
            return string.Format("{0}{1}-{2}-{3} {4}:{5}:{6}", _yearPart2, _yearPart1, _month, _day, _hour, _minute, _second);
        }
        #endregion
        #region 将dateTime转换其对应的BCD码
        /// <summary>
        /// 将dateTime转换其对应的BCD码
        /// <para>eg:StringHelper.DateTimeBCDFormart(new DateTime(2012, 11, 18, 20, 21, 22));==>22212018111220</para>
        /// </summary>
        /// <param name="dateTime">DateTime</param>
        /// <returns>BCD码</returns>
        public static string DateTimeBCDFormart(DateTime dateTime)
        {
            string _second = dateTime.Second.ToString().PadLeft(2, '0');
            string _minute = dateTime.Minute.ToString().PadLeft(2, '0');
            string _hour = dateTime.Hour.ToString().PadLeft(2, '0');
            string _day = dateTime.Day.ToString().PadLeft(2, '0');
            string _month = dateTime.Month.ToString().PadLeft(2, '0');
            string _yearFull = dateTime.Year.ToString();
            string _yearRev = string.Format("{0}{1}", _yearFull.Substring(2, 2), _yearFull.Substring(0, 2));
            return string.Format("{0}{1}{2}{3}{4}{5}", _second, _minute, _hour, _day, _month, _yearRev);
        }
        #endregion
        #region 四位长度的字符串高低位互换
        /// <summary>
        /// 四位长度的字符串高低位互换
        ///<para>eg:StringHelper.ExchangeHightToLow("1122");==>2211</para> 
        /// </summary>
        /// <param name="data">需要操作的字符串</param>
        /// <returns>高低位互换字符串</returns>
        public static string ExchangeHightToLow(string data)
        {
            if (!string.IsNullOrEmpty(data))
            {
                data = data.Trim();
                if (data.Length != 4)
                    throw new ArgumentException(string.Format("四位长度的字符串高低位互换，需要参数长度为四位，而传入参数:{0}，长度为:{1}.", data, data.Length));
                return string.Format("{0}{1}", data.Substring(2, 2), data.Substring(0, 2));
            }
            return data;
        }
        #endregion
        #region 检查decimal 在符号.之前有多少长度 eg:12.121表示两个长度
        /// <summary>
        /// 检查decimal 在符号.之前有多少长度
        ///<para>eg:StringHelper.MaxThanDecimal("123.45", out _value, 3);==>true</para>
        ///<para>remark:12.121表示两个长度</para>
        /// </summary>
        /// <param name="decimalData">需要检查的decimal</param>
        /// <param name="val">返回的decimal</param>
        /// <param name="decimalLen"> 至少多少长度eg:12.121表示两个长度</param>
        /// <returns></returns>
        public static bool MaxThanDecimal(string decimalData, out decimal val, int decimalLen)
        {
            if (!decimal.TryParse(decimalData, out val))
                return false;
            int _separatorIndex = decimalData.LastIndexOf(NumberFormatInfo.CurrentInfo.NumberDecimalSeparator);
            return ((_separatorIndex != -1 && _separatorIndex <= decimalLen) || (_separatorIndex == -1 && decimalData.Length <= decimalLen));
        }
        #endregion
        #region 清除字符串内空格
        /// <summary>
        /// 清除字符串内空格
        /// <para>eg:StringHelper.ExceptBlanks(" 11 22 33 44  ");==>11223344</para>
        /// </summary>
        /// <param name="data">需要处理的字符串</param>
        /// <returns>处理好后的字符串</returns>
        public static string ExceptBlanks(this string data)
        {
            int _length = data.Length;
            if (_length > 0)
            {
                StringBuilder _builder = new StringBuilder(_length);
                for (int i = 0; i < data.Length; i++)
                {
                    char _c = data[i];
                    //switch (_c)
                    //{
                    //    case '\r':
                    //    case '\n':
                    //    case '\t':
                    //    case ' ':
                    //        continue;
                    //    default:
                    //        _builder.Append(_c);
                    //        break;
                    //}
                    if (!char.IsWhiteSpace(_c))
                        _builder.Append(_c);
                }
                return _builder.ToString();
            }
            return data;
        }
        #endregion
        #region 反转字符串几种方式
        /// <summary>
        /// 利用Array.Reverse反转字符串
        /// </summary>
        /// <param name="data">操作字符串</param>
        /// <returns>反转字符串</returns>
        public static string ReverseUsingArrayClass(this string data)
        {
            if (!string.IsNullOrEmpty(data))
            {
                char[] _chars = data.ToCharArray();
                Array.Reverse(_chars);
                return new string(_chars);
            }
            return data;
        }
        /// <summary>
        /// 利用遍历反转字符串
        /// </summary>
        /// <param name="data">操作字符串</param>
        /// <returns>反转字符串</returns>
        public static string ReverseUsingCharacterBuffer(this string data)
        {
            if (data.Length > 0)
            {
                char[] _charArray = new char[data.Length];
                int _inputStrLength = data.Length - 1;
                for (int i = 0; i <= _inputStrLength; i++)
                {
                    _charArray[i] = data[_inputStrLength - i];
                }
                return new string(_charArray);
            }
            return data;
        }
        /// <summary>
        /// 利用StringBuilder反转字符串
        /// </summary>
        /// <param name="data">操作字符串</param>
        /// <returns>反转字符串</returns>
        public static string ReverseUsingStringBuilder(this string data)
        {
            if (data.Length > 0)
            {
                StringBuilder _builder = new StringBuilder(data.Length);
                for (int i = data.Length - 1; i >= 0; i--)
                {
                    _builder.Append(data[i]);
                }
                return _builder.ToString();
            }
            return data;
        }
        /// <summary>
        /// 利用Stack反转字符串
        /// </summary>
        /// <param name="data">操作字符串</param>
        /// <returns>反转字符串</returns>
        public static string ReverseUsingStack(this string data)
        {
            if (data.Length > 0)
            {
                Stack<char> _resultStack = new Stack<char>();
                foreach (char c in data)
                {
                    _resultStack.Push(c);
                }
                StringBuilder _builder = new StringBuilder();
                while (_resultStack.Count > 0)
                {
                    _builder.Append(_resultStack.Pop());
                }
                return _builder.ToString();
            }
            return data;
        }
        /// <summary>
        /// 利用XOR反转字符串
        /// </summary>
        /// <param name="data">操作字符串</param>
        /// <returns>反转字符串</returns>
        public static string ReverseUsingXOR(this string data)
        {
            if (data.Length > 0)
            {
                char[] _charArray = data.ToCharArray();
                int _length = data.Length - 1;
                for (int i = 0; i < _length; i++, _length--)
                {
                    _charArray[i] ^= _charArray[_length];
                    _charArray[_length] ^= _charArray[i];
                    _charArray[i] ^= _charArray[_length];
                }
                return new string(_charArray);
            }
            return data;
        }
        #endregion
        #region  对字符串遍历分割
        /// <summary>
        /// 对字符串遍历分割
        /// <para>eg: StringHelper.BuilderDelimiter("Yan", '-');==>"Y-a-n"</para>
        /// </summary>
        /// <param name="data">需要分割的字符串</param>
        /// <param name="delimiter">每个字符分割符号</param>
        /// <returns>分割好的字符串</returns>
        public static string BuilderDelimiter(this string data, char delimiter)
        {
            if (!string.IsNullOrEmpty(data))
            {
                char[] _chars = data.ToCharArray();
                StringBuilder _builder = new StringBuilder();
                foreach (char c in _chars)
                {
                    _builder.AppendFormat("{0}{1}", c, delimiter);
                }
                string _resultStr = _builder.ToString();
                int _invalid = _resultStr.LastIndexOf(delimiter);
                if (_invalid != -1)
                {
                    _resultStr = _resultStr.Substring(0, _invalid);
                }
                return _resultStr;
            }
            return string.Empty;
        }
        #endregion
        #region 遍历字符串
        /// <summary>
        /// 遍历字符串
        /// <para>eg: StringHelper.LoopString("YanZhiwei", c => '1');==>"111111111"</para>
        /// </summary>
        /// <param name="data">需要遍历的字符串</param>
        /// <param name="loopFactory">带char类型的输入类型参数的委托</param>
        /// <returns>处理好的字符串</returns>
        public static string LoopString(this string data, Func<char, char> loopFactory)
        {
            if (!string.IsNullOrEmpty(data))
            {
                StringBuilder _builder = new StringBuilder();
                char[] _chars = data.ToCharArray();
                foreach (char c in _chars)
                {
                    _builder.Append(loopFactory(c));
                }
                return _builder.ToString();
            }
            return string.Empty;
        }
        #endregion
        #region 遍历字符串，查找出字符串中符合委托的索引
        /// <summary>
        /// 遍历字符串，查找出字符串中符合委托的索引
        /// </summary>
        /// <param name="data"></param>
        /// <param name="offset">偏移量</param>
        /// <param name="validFactory">委托</param>
        /// <returns>符合委托规则的会合Index</returns>
        public static string ValidIndex(this string data, int offset, Predicate<char> validFactory)
        {
            if (!string.IsNullOrEmpty(data))
            {
                StringBuilder _builder = new StringBuilder();
                char[] _chars = data.ToCharArray();
                int i = 0;
                foreach (char c in _chars)
                {
                    if (validFactory(c))
                        _builder.Append(offset + i);
                    i++;
                }
                return _builder.ToString();
            }
            return string.Empty;
        }
        #endregion
        #region 文字换行
        /// <summary>
        /// 文字换行
        /// <para>eg:StringHelper.WrapText("YanZhiwei", 3);==>"Yan\r\nZhi\r\nwei"</para>
        /// </summary>
        /// <param name="data">需要换行的文字</param>
        /// <param name="maxWidth">多少长度换行</param>
        /// <returns>换行好的文字</returns>
        public static string WrapText(this string data, int maxWidth)
        {
            int _stringCount = data.Length;
            if (maxWidth > 0 && _stringCount > maxWidth)
            {
                StringBuilder _builderString = new StringBuilder(data);
                int _breakCount = _builderString.Length / maxWidth;
                for (int i = 0; i < _breakCount; i++)
                {
                    int _insertPosition = i * maxWidth;
                    if (_insertPosition != 0)
                    {
                        int _offset = (i - 1) * 2;//(\r\n)
                        _builderString.Insert(_insertPosition + _offset, Environment.NewLine);
                    }
                }
                return _builderString.ToString();
            }
            else
            {
                return data;
            }
        }
        #endregion
        #region 按照符号截取字符串
        /// <summary>
        /// 按照符号截取字符串
        ///<para>eg:StringHelper.SubstrIndexOf("Yan&Zhiwei", '&');==>"Yan"</para>
        /// </summary>
        /// <param name="data">需要截取的字符串</param>
        /// <param name="delimiter">判断符号</param>
        /// <returns>截取好的字符串</returns>
        public static string Remove(this string data, char delimiter)
        {
            if (!string.IsNullOrEmpty(data))
            {
                int _indexof = data.IndexOf(delimiter);
                if (_indexof != -1)
                {
                    data = data.Substring(0, _indexof);
                }
            }
            return data;
        }
        #endregion
        #region 按照最后符号截取字符串
        /// <summary>
        /// 按照最后符号截取字符串
        /// <para>StringHelper.SubstrLastIndexOf("YanZhiwei&", '&');==>"YanZhiwei"</para>
        /// </summary>
        /// <param name="data">需要截取的字符串</param>
        /// <param name="delimiter">判断符号</param>
        /// <returns>截取好的字符串</returns>
        public static string RemoveLast(this string data, char delimiter)
        {
            if (!string.IsNullOrEmpty(data))
            {
                int _indexof = data.LastIndexOf(delimiter);
                if (_indexof != -1)
                {
                    data = data.Substring(0, _indexof);
                }
            }
            return data;
        }
        #endregion
        #region 获取MD5加密字符串
        /// <summary>
        /// 获取MD5加密字符串
        ///<para>参考：http://www.dotblogs.com.tw/chhuang/archive/2008/05/17/4029.aspx </para> 
        ///<para>eg:StringHelper.ToMD5("YanZhiwei");==>"b07ec574a666d8e7582885ce334b4d00"</para>
        /// </summary>
        /// <param name="data">需要加密的字符串</param>
        /// <returns>MD5加密的字符串</returns>
        public static string ToMD5(this string data)
        {
            if (!string.IsNullOrEmpty(data))
            {
                MD5CryptoServiceProvider _md5 = new MD5CryptoServiceProvider();
                byte[] _bytValue = Encoding.UTF8.GetBytes(data);
                byte[] _bytHash = _md5.ComputeHash(_bytValue);
                _md5.Clear();
                StringBuilder _builder = new StringBuilder();
                for (int i = 0; i < _bytHash.Length; i++)
                {
                    _builder.Append(_bytHash[i].ToString("X").PadLeft(2, '0'));
                }
                return _builder.ToString().ToLower();
            }
            return string.Empty;
        }
        #endregion
        #region 将千分位字符串转换成数字
        /// <summary>
        /// 将千分位字符串转换成数字
        /// <para>eg:StringHelper.ParseThousandthString("111,222,333");==>111222333</para>
        /// </summary>
        /// <param name="data">需要转换的千分位</param>
        /// <returns>数字;若转换失败则返回-1</returns>
        public static int ParseThousandthString(this string data)
        {
            int _value = -1;
            if (!string.IsNullOrEmpty(data))
            {
                try
                {
                    _value = int.Parse(data, NumberStyles.AllowThousands | NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign);
                }
                catch (Exception ex)
                {
                    _value = -1;
                    Debug.WriteLine(string.Format("将千分位字符串{0}转换成数字异常，原因:{0}", data, ex.Message));
                }
            }
            return _value;
        }
        #endregion
        #region 判断字符串长度
        /// <summary>
        /// 判断字符串长度
        /// <para>eg:StringHelper.EqualLength("YanZhiwei", 9);==>true</para>
        /// </summary>
        /// <param name="data">需要判断的字符串</param>
        /// <param name="length">需要等于的长度</param>
        /// <returns>是否等于期待的字符串长度</returns>
        public static bool EqualLength(this string data, int length)
        {
            bool _result = false;
            if (data != null)
            {
                int _length = data.Length;
                _result = _length == length;
            }
            return _result;
        }
        #endregion
        #region 截取字符串
        /// <summary>
        /// 截取字符串,超过最大长度则以'...'表示
        /// </summary>
        /// <param name="data">需要截取的字符串</param>
        /// <param name="maxLen">字符串最大长度，超过最大长度则以'...'表示</param>
        /// <returns>截取后字符串</returns>
        public static string Substring(this string data, int maxLen)
        {
            if (maxLen <= 0)
            {
                return data;
            }
            else
            {
                if (data.Length > maxLen)
                {
                    return data.Substring(0, maxLen) + "...";
                }
                else
                {
                    return data;
                }
            }
        }
        #endregion
        #region 补足位数
        /// <summary>
        /// 补足位数_右边
        /// <para>eg:StringHelper.ComplementRigthZero("Yanzhiwei", 15);==>Yanzhiwei000000</para>
        /// </summary>
        /// <param name="data">需要操作的字符串</param>
        /// <param name="targetLength">目标长度</param>
        /// <returns>操作完成后字符串</returns>
        public static string ComplementRigthZero(this string data, int targetLength)
        {
            int _curLength = data.Length;
            if (_curLength < targetLength)
            {
                StringBuilder _builder = new StringBuilder(targetLength);
                _builder.Append(data);
                for (int i = 0; i < targetLength - data.Length; i++)
                {
                    _builder.Append("0");
                }
                return _builder.ToString();
            }
            return data;
        }
        /// <summary>
        /// 补足位数_左边
        /// <para>eg:StringHelper.ComplementLeftZero("Yanzhiwei", 15);==>"000000Yanzhiwei"</para>
        /// </summary>
        /// <param name="data">需要操作的字符串</param>
        /// <param name="targetLength">目标长度</param>
        /// <returns>操作完成后字符串</returns>
        public static string ComplementLeftZero(this string data, int targetLength)
        {
            int _curLength = data.Length;
            if (_curLength < targetLength)
            {
                StringBuilder _builder = new StringBuilder(targetLength);
                for (int i = 0; i < targetLength - data.Length; i++)
                {
                    _builder.Append("0");
                }
                _builder.Append(data);
                return _builder.ToString();
            }
            return data;
        }
        #endregion
    }
}